package wavenotes;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;

import javax.jdo.PersistenceManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONException;

import wavenotes.model.PMF;
import wavenotes.model.presentation.Presentation;
import wavenotes.model.presentation.Slide;
import wavenotes.robot.NewRobotServlet;

import com.google.appengine.api.datastore.KeyFactory;
import com.google.inject.Inject;
import com.google.inject.Singleton;

import flexjson.DateTransformer;
import flexjson.JSONDeserializer;

@Singleton
public class PresentationServlet extends HttpServlet
{
	private static final long serialVersionUID = -8078836733289988014L;
	
	@Inject
	private NewRobotServlet robot;

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
	{
		if (req.getContentType().equals("application/json"))
			handleCreateRequest(req, resp);
		else
			handleSynchronizationRequest(req, resp);
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
	{
		if ("sync".equals(req.getParameter("method")))
			handleSynchronizationRequest(req, resp);
		else if ("list".equals(req.getParameter("method")))
			handleListingRequest(req, resp);
		else
		{
			if (null != req.getParameter("presentationKey"))
				jsonPresentation(req, resp);
		}
	}

	/**
	 * Handles the listing request. Sends back a json object with the list of
	 * presentations belonging to a specific author
	 * 
	 * @param req
	 * @param resp
	 * @throws ServletException
	 * @throws IOException
	 */
	private void handleListingRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			String creator = req.getParameter("creator");
			if (creator == null)
				throw new ServletException("You must specify a creator");

			String jsonResponse = Presentation.getPresentationList(creator, pm);
			resp.setContentType("application/json");
			resp.getWriter().print(jsonResponse);
			resp.getWriter().flush();
		}
		finally
		{
			pm.close();
		}
	}

	/**
	 * Sends back a JSON representation of a presentation
	 * 
	 * @param req
	 * @param resp
	 * @throws ServletException
	 * @throws IOException
	 */
	protected void jsonPresentation(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();

		try
		{
			String presentationKey = req.getParameter("presentationKey");
			String jsoncallback = req.getParameter("jsoncallback");
			Presentation presentation = pm.getObjectById(Presentation.class, presentationKey);

			if (null == presentation)
				throw new ServletException("Presentation with key " + presentationKey + " not found.");

			try
			{
				resp.setContentType("application/json");
				String json = presentation.toJSON().toString();

				if (null != jsoncallback)
					json = jsoncallback + "(" + json + ");";

				resp.getWriter().print(json);
			}
			catch (JSONException e)
			{
				e.printStackTrace();
			}

		}
		finally
		{
			pm.close();
		}
	}

	/**
	 * Saves a presentation in the datastore. Outputs the key.
	 * 
	 * @param req
	 * @param resp
	 * @throws IOException
	 */
	protected void handleCreateRequest(HttpServletRequest req, HttpServletResponse resp) throws IOException
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();

		// create presentation request
		try
		{
			byte[] jsonInput = new byte[req.getContentLength()];
			req.getInputStream().read(jsonInput);
			String jsonString = new String(jsonInput);
			
			Presentation newPresentation = new JSONDeserializer<Presentation>().use(null, Presentation.class)
						.use("slides", ArrayList.class)
						.use("slides.values", Slide.class)
						.use(Date.class, new DateTransformer("yyyy.MM.dd"))
						.deserialize(jsonString);
			newPresentation = (Presentation)pm.makePersistent(newPresentation);
			resp.getWriter().print(KeyFactory.keyToString(newPresentation.getKey()));
		}
		catch (Exception e)
		{
			System.err.println(e);
			e.printStackTrace();
		}
		finally
		{
			pm.close();
		}
	}

	/**
	 * Sets the slide index for a presentation.
	 * 
	 * @param req
	 * @param resp
	 * @throws ServletException
	 */
	protected void handleSynchronizationRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			String presentationKey = null;
			int slideIndex = 0;
			if (null == (presentationKey = req.getParameter("presentationKey")))
				throw new ServletException("Invalid presentationKey: " + presentationKey);

			if (null == req.getParameter("slideIndex"))
				throw new ServletException("Invalid slideIndex: " + slideIndex);
			else
				slideIndex = Integer.parseInt(req.getParameter("slideIndex"));

			Presentation presentation = pm.getObjectById(Presentation.class, presentationKey);

			if (null == presentation)
				throw new ServletException("Presentation with key " + presentationKey + " not found.");

			if (slideIndex < 0 || slideIndex >= presentation.getSlides().size())
				throw new ServletException("Slide index " + slideIndex + " out of range.");

			presentation.setCurrentSlideIndex(slideIndex);
		}
		finally
		{
			pm.close();
		}
	}
}
